package com.smartleanx.module.hrm.service.esign.auth.impl;

import cn.hutool.core.util.StrUtil;
import com.smartleanx.module.hrm.service.esign.auth.EsignCommonService;
import com.smartleanx.module.hrm.service.esign.temp.vo.Auth.*;
import com.smartleanx.module.hrm.service.examine.util.exception.EsignException;
import com.smartleanx.module.hrm.util.esign.enums.EsignRequestType;
import com.smartleanx.module.hrm.util.esign.enums.IDCardType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.List;

import static com.smartleanx.module.hrm.util.esign.constant.OrgAuthMode.ORG_COMMON_MODE;
import static com.smartleanx.module.hrm.util.esign.constant.OrgAuthMode.ORG_LEGALREP_INVOLVED;
import static com.smartleanx.module.hrm.util.esign.constant.OrgAuthScope.ORG_COMMON_SCOPE;
import static com.smartleanx.module.hrm.util.esign.constant.PsnAuthMode.PSN_COMMON_MODE;
import static com.smartleanx.module.hrm.util.esign.constant.PsnAuthMode.PSN_MOBILE3;
import static com.smartleanx.module.hrm.util.esign.constant.PsnAuthScope.PSN_COMMON_SCOPE;
import static com.smartleanx.module.hrm.util.esign.enums.IDCardType.CRED_ORG_USCC;
import static com.smartleanx.module.hrm.util.esign.enums.IDCardType.CRED_PSN_CH_IDCARD;

@Service
public class ESignAuthServiceImpl extends EsignCommonService {
    @Autowired
    private EsignProperties properties;

    /**
     * 【通用】获取个人认证&授权页面链接
     *
     * @param psnAccount 账号
     * @param psnName 姓名
     * @param psnIdCardNum 身份证号
     *
     * @apiNote 身份信息：大陆身份证+身份证号 <br/>
     *          默认认证方式：手机号三要素 <br/>
     *          可选认证方式：手机号三要素、银行卡四要素，人脸 <br/>
     *          授权范围：全部 <br/>
     *          无重定向、无自定义回调通知
     */
    public PsnAuthResp getPsnAuthUrl(String psnAccount, String psnName, String psnIdCardNum) throws EsignException {
        return getPsnAuthUrl(psnAccount, psnName, psnIdCardNum, null);
    }

    /**
     * 【通用】获取个人认证&授权页面链接
     *
     * @param psnAccount 账号
     * @param psnName 姓名
     * @param psnIdCardNum 身份证号
     * @param redirectUrl 重定向全路径
     *
     * @apiNote 身份信息：大陆身份证+身份证号 <br/>
     *          默认认证方式：手机号三要素 <br/>
     *          可选认证方式：手机号三要素、银行卡四要素，人脸 <br/>
     *          授权范围：全部
     */
    public PsnAuthResp getPsnAuthUrl(String psnAccount, String psnName, String psnIdCardNum, String redirectUrl) throws EsignException {
        return getPsnAuthUrl(psnAccount, psnName, null, psnIdCardNum, PSN_MOBILE3, PSN_COMMON_MODE,
                PSN_COMMON_SCOPE, redirectUrl);
    }

    /**
     * 【通用】获取个人认证&授权页面链接
     *
     * @param psnAccount 账号
     * @param psnName 姓名
     * @param psnIDCardType 证件类型
     * @param psnIdCardNum 证件号码
     * @param psnDefaultAuthMode 默认认证方式
     * @param psnAvailableAuthModes 可选认证方式
     * @param authorizedScopes 授权范围
     * @param redirectUrl 认证完成重定向地址
     */
    public PsnAuthResp getPsnAuthUrl(String psnAccount, String psnName, IDCardType psnIDCardType, String psnIdCardNum,
                                     String psnDefaultAuthMode, List<String> psnAvailableAuthModes, List<String> authorizedScopes,
                                     String redirectUrl) throws EsignException {
        // 构建请求体
        PsnAuthReq psnAuthReq = PsnAuthReq.builder()
                // 认证配置
                .psnAuthConfig(PsnAuthConfig.builder()
                        // 认证配置：个人用户账号标识
                        .psnAccount(psnAccount)
                        // 认证配置：个人身份附加信息
                        .psnInfo(PsnInfo.builder()
                                // 个人身份：姓名
                                .psnName(psnName)
                                // 个人身份：身份证
                                .psnIDCardType(psnIDCardType)
                                // 个人身份：身份证号
                                .psnIDCardNum(psnIdCardNum).build())
                        // 认证配置：页面配置
                        .psnAuthPageConfig(PsnAuthPageConfig.builder()
                                // 页面配置：默认认证方式
                                .psnDefaultAuthMode(psnDefaultAuthMode)
                                // 页面配置：可选认证方式
                                .psnAvailableAuthModes(psnAvailableAuthModes).build())
                        .build())
                // 授权配置
                .authorizeConfig(AuthorizeConfig.builder().authorizedScopes(authorizedScopes).build())
                // 重定向配置
                .redirectConfig(RedirectConfig.builder().redirectUrl(redirectUrl).build())
                // 回调配置
                .build();
        return getPsnAuthUrl(psnAuthReq);
    }

    /**
     * 【通用】获取个人授权页面链接
     *
     * @param psnId 账号ID
     * @param authorizedScopes 授权范围
     * @param redirectUrl 认证完成重定向地址
     */
    public PsnAuthResp getPsnAuthUrl(String psnId, List<String> authorizedScopes, String redirectUrl)
            throws EsignException {
        // 构建请求体
        PsnAuthReq psnAuthReq = PsnAuthReq.builder()
                // 认证配置
                .psnAuthConfig(PsnAuthConfig.builder()
                        // 认证配置：个人用户账号ID
                        .psnId(psnId).build())
                // 授权配置
                .authorizeConfig(AuthorizeConfig.builder().authorizedScopes(authorizedScopes).build())
                // 重定向配置
                .redirectConfig(RedirectConfig.builder().redirectUrl(redirectUrl).build())
                // 回调配置
                .build();
        return getPsnAuthUrl(psnAuthReq);
    }

    /**
     * 获取个人认证&授权页面链接
     */
    public PsnAuthResp getPsnAuthUrl(PsnAuthReq param) throws EsignException {
        String apiAddr = "/v3/psn-auth-url";
        return baseRequest(properties, EsignRequestType.POST, apiAddr, param, PsnAuthResp.class);
    }

    /**
     * 查询个人认证信息
     *
     * @param psnId 个人账号ID
     * @param psnAccount 个人账号标识（手机号或邮箱）
     * @param psnIdCardNum 个人用户的证件号
     * @param cardType 个人证件号类型 （传psnIDCardNum时，证件类型为必传项）
     *
     * @apiNote 查询优先级为 psnId > psnAccount > psnIDCardNum
     */
    public PsnIdentityInfoResp getPsnIdentityInfo(String psnId, String psnAccount, String psnIdCardNum,
                                                  IDCardType cardType) throws EsignException {
        // 根据参数拼接地址
        StringBuilder apiAddr = new StringBuilder("/v3/persons/identity-info?");
        if (!StrUtil.isEmpty(psnId)) {
            apiAddr.append("psnId=").append(psnId);
        } else if (!StrUtil.isEmpty(psnAccount)) {
            apiAddr.append("psnAccount=").append(psnAccount);
        } else if (!StrUtil.isEmpty(psnIdCardNum) && cardType != null) {
            apiAddr.append("psnIDCardNum=").append(psnIdCardNum).append("&psnIDCardType=").append(cardType.name());
        } else {
            throw new EsignException("请求参数缺失");
        }
        return baseRequest(properties, EsignRequestType.GET, apiAddr.toString(), null, PsnIdentityInfoResp.class);
    }

    /**
     * 查询个人授权信息
     *
     * @param psnId 个人账号ID（或企业经办人账号ID）
     *
     * @apiNote 个人授权场景：用于查询个人用户授权开发者应用（AppId）的范围，以及授权有效期限；<br/>
     *          企业授权场景：用于查询企业经办人授权开发者应用（AppId）的范围，以及授权有效期限；
     */
    public AuthorizedInfoResp getPsnAuthorizedInfo(String psnId) throws EsignException {
        // 根据参数拼接地址
        String apiAddr = "/v3/persons/%s/authorized-info";
        if (!StrUtil.isEmpty(psnId)) {
            apiAddr = String.format(apiAddr, psnId);
        } else {
            throw new EsignException("请求参数缺失");
        }
        return baseRequest(properties, EsignRequestType.GET, apiAddr, null, AuthorizedInfoResp.class);
    }

    /**
     * 【通用】获取机构认证&授权链接
     *
     * @param orgName 组织/机构名称
     * @param creditCode 统一社会信用代码
     * @param legalRepName 法人姓名
     * @param psnId 经办人账号ID
     * @param redirectUrl 重定向地址
     * @param transactorUseSeal 经办人非企业管理员的情况下，是否需要为其获取企业全部印章的用印权限，默认false
     *
     * @apiNote 经办人已完成个人认证
     */
    public OrgAuthResp getOrgAuthUrl(String orgName, String creditCode, String legalRepName, String psnId,
                                     String redirectUrl, boolean transactorUseSeal) throws EsignException {
        return getOrgAuthUrl(orgName, creditCode, legalRepName, null, null, psnId, redirectUrl, transactorUseSeal);
    }

    /**
     * 【通用】获取机构认证&授权链接
     *
     * @param orgName 组织/机构名称
     * @param creditCode 统一社会信用代码
     * @param legalRepName 法人姓名
     * @param legalRepIDCardNum 法定代表人证件号
     * @param psnId 经办人账号ID
     * @param redirectUrl 重定向地址
     * @param transactorUseSeal 经办人非企业管理员的情况下，是否需要为其获取企业全部印章的用印权限，默认false
     *
     * @apiNote 经办人已完成个人认证
     */
    public OrgAuthResp getOrgAuthUrl(String orgName, String creditCode, String legalRepName,
                                     IDCardType legalRepIDCardType, String legalRepIDCardNum, String psnId, String redirectUrl,
                                     boolean transactorUseSeal) throws EsignException {
        return getOrgAuthUrl(orgName, ObjectUtils.isEmpty(creditCode)?null:CRED_ORG_USCC, creditCode, legalRepName, legalRepIDCardType, legalRepIDCardNum,
                ORG_LEGALREP_INVOLVED, ORG_COMMON_MODE, psnId, null, null, null, null, null, null, null, null,
                ORG_COMMON_SCOPE, redirectUrl, transactorUseSeal);
    }

    /**
     * 【通用】获取机构认证&授权链接
     *
     * @param orgName 组织/机构名称
     * @param orgIDCardType 组织/机构证件类型
     * @param orgIDCardNum 组织机构证件号
     * @param legalRepName 法人姓名
     * @param legalRepIDCardType 法定代表人证件类型
     * @param legalRepIDCardNum 法定代表人证件号
     * @param orgDefaultAuthMode 默认选择的机构认证方式
     * @param orgAvailableAuthModes 可选择的机构认证方式
     * @param psnId 经办人账号ID
     * @param psnAccount 经办人账号标识
     * @param psnName 经办人姓名
     * @param psnIDCardType 经办人证件类型
     * @param psnIDCardNum 经办人证件号
     * @param psnBankCardNum 经办人银行卡号
     * @param psnMobile 经办人手机号（运营商实名登记手机号或银行卡预留手机号，仅用于认证）
     * @param psnDefaultAuthMode 默认选择的经办人认证方式
     * @param psnAvailableAuthModes 可选择的经办人认证方式
     * @param authorizedScopes 授权范围
     * @param redirectUrl 重定向地址
     * @param transactorUseSeal 经办人非企业管理员的情况下，是否需要为其获取企业全部印章的用印权限，默认false
     *
     * @apiNote 公共方法
     */
    public OrgAuthResp getOrgAuthUrl(String orgName, IDCardType orgIDCardType, String orgIDCardNum, String legalRepName,
                                     IDCardType legalRepIDCardType, String legalRepIDCardNum, String orgDefaultAuthMode,
                                     List<String> orgAvailableAuthModes, String psnId, String psnAccount, String psnName, IDCardType psnIDCardType,
                                     String psnIDCardNum, String psnBankCardNum, String psnMobile, String psnDefaultAuthMode,
                                     List<String> psnAvailableAuthModes, List<String> authorizedScopes, String redirectUrl,
                                     boolean transactorUseSeal) throws EsignException {
        // 构建请求体
        OrgAuthReq orgAuthReq = OrgAuthReq.builder()
                // 认证配置
                .orgAuthConfig(OrgAuthConfig.builder()
                        // 认证配置：组织/机构名称
                        .orgName(orgName)
                        // 认证配置：组织/机构身份附加信息
                        .orgInfo(OrgInfo.builder()
                                // 身份信息：组织/机构证件类型
                                .orgIDCardType(orgIDCardType)
                                // 身份信息：组织机构证件号
                                .orgIDCardNum(orgIDCardNum)
                                // 身份信息：法人姓名
                                .legalRepName(legalRepName)
                                // 身份信息：法定代表人证件类型
                                .legalRepIDCardType(legalRepIDCardType)
                                // 身份信息：法定代表人证件号
                                .legalRepIDCardNum(legalRepIDCardNum).build())
                        // 认证配置：机构实名认证页面配置项
                        .orgAuthPageConfig(OrgAuthPageConfig.builder()
                                // 页面配置：默认选择的机构认证方式
                                .orgDefaultAuthMode(orgDefaultAuthMode)
                                // 页面配置：可选择的机构认证方式
                                .orgAvailableAuthModes(orgAvailableAuthModes).build())
                        // 认证配置：经办人身份信息
                        .transactorInfo(PsnAuthConfig.builder()
                                // 经办人信息：经办人账号ID
                                .psnId(psnId)
                                // 经办人信息：经办人账号标识
                                .psnAccount(psnAccount)
                                // 经办人信息：经办人附加信息
                                .psnInfo(PsnInfo.builder()
                                        // 经办人：姓名
                                        .psnName(psnName)
                                        // 经办人：身份证
                                        .psnIDCardType(psnIDCardType)
                                        // 经办人：身份证号
                                        .psnIDCardNum(psnIDCardNum)
                                        // 经办人：银行卡号
                                        .bankCardNum(psnBankCardNum)
                                        // 经办人：经办人手机号（运营商实名登记手机号或银行卡预留手机号，仅用于认证）
                                        .psnMobile(psnMobile).build())
                                .build())
                        // 认证配置：经办人认证页面配置
                        .transactorAuthPageConfig(PsnAuthPageConfig.builder()
                                // 页面配置：默认选择的经办人认证方式
                                .psnDefaultAuthMode(psnDefaultAuthMode)
                                // 页面配置：可选择的经办人认证方式
                                .psnAvailableAuthModes(psnAvailableAuthModes).build())
                        .build())
                // 授权配置
                .authorizeConfig(AuthorizeConfig.builder().authorizedScopes(authorizedScopes).build())
                // 重定向配置
                .redirectConfig(RedirectConfig.builder().redirectUrl(redirectUrl).build())
                // 当前经办人非企业管理员的情况下，是否需要为其获取企业全部印章的用印权限，默认false
                .transactorUseSeal(transactorUseSeal)
                // 接收回调通知的Web地址，可携带url参数
               .build();
        return getOrgAuthUrl(orgAuthReq);
    }

    /**
     * 获取机构认证&授权页面链接
     */
    public OrgAuthResp getOrgAuthUrl(OrgAuthReq param) throws EsignException {
        String apiAddr = "/v3/org-auth-url";
        return baseRequest(properties, EsignRequestType.POST, apiAddr, param, OrgAuthResp.class);
    }

    /**
     * 查询机构认证信息
     *
     * @param orgId 机构账号ID
     * @param orgName 组织机构名称
     * @param orgIdCardNum 组织机构证件号
     * @param orgIdCardType 组织机构证件类型（传orgIDCardNum时，该参数为必传）
     *
     * @apiNote 查询优先级为 orgId > orgName > orgIDCardNum
     */
    public OrgIdentityInfoResp getOrgIdentityInfo(String orgId, String orgName, String orgIdCardNum,
                                                  IDCardType orgIdCardType) throws EsignException {
        // 根据参数拼接地址
        StringBuilder apiAddr = new StringBuilder("/v3/organizations/identity-info?");
        if (!StrUtil.isEmpty(orgId)) {
            apiAddr.append("orgId=").append(orgId);
        } else if (!StrUtil.isEmpty(orgName)) {
            apiAddr.append("orgName=").append(orgName);
        } else if (!StrUtil.isEmpty(orgIdCardNum) && orgIdCardType != null) {
            apiAddr.append("orgIDCardNum=").append(orgIdCardNum).append("&orgIDCardType=").append(orgIdCardType.name());
        } else {
            throw new EsignException("请求参数缺失");
        }
        return baseRequest(properties, EsignRequestType.GET, apiAddr.toString(), null, OrgIdentityInfoResp.class);
    }

    /**
     * 查询机构授权信息
     *
     * @param orgId 机构账号ID
     *
     * @apiNote 通过指定企业账号ID，来查询组织机构用户的授权范围以及授权的有效期限。
     */
    public AuthorizedInfoResp getOrgAuthorizedInfo(String orgId) throws EsignException {
        // 根据参数拼接地址
        String apiAddr = "/v3/organizations/%s/authorized-info";
        if (!StrUtil.isEmpty(orgId)) {
            apiAddr = String.format(apiAddr, orgId);
        } else {
            throw new EsignException("请求参数缺失");
        }
        return baseRequest(properties, EsignRequestType.GET, apiAddr, null, AuthorizedInfoResp.class);
    }

    /**
     * 查询认证授权流程详情
     *
     * @param authFlowId 认证/授权流程ID
     */
    public AuthFlowResultResp getAuthFlowResult(String authFlowId) throws EsignException {
        String apiAddr = "/v3/auth-flow/" + authFlowId;
        return baseRequest(properties, EsignRequestType.GET, apiAddr, null, AuthFlowResultResp.class);
    }


}
